home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / BMUTIL.C < prev    next >
C/C++ Source or Header  |  1997-08-18  |  51KB  |  2,057 lines

  1. /*
  2.  *    Simple mail user interface for KA9Q IP/TCP package.
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *    Copyright 1987 1988 Dave Trulli NN2Z, All Rights Reserved.
  8.  *    Permission granted for non-commercial copying and use, provided
  9.  *    this notice is retained.
  10.  *
  11.  *    Ported to NOS at 900120 by Anders Klemets SM0RGV.
  12.  *
  13.  *  Userlogging, 'RM' and 'KM' implementation,
  14.  *  more-prompts for all types
  15.  *  920307 and later, by Johan. K. Reinalda, WG7J/PA3DIS
  16.  *  920719 and later, by Brian A. Lantz, KO4KS
  17.  */
  18. #include "global.h"
  19. #include "ctype.h"
  20. #include "commands.h"
  21. #include "files.h"
  22. #ifdef MSDOS
  23. #include <io.h>
  24. #else
  25. #include <time.h>
  26. #endif
  27. #include "ftpserv.h"
  28. #include "smtp.h"
  29. #include "proc.h"
  30. #include "usock.h"
  31. #include "telnet.h"
  32. #include "mailbox.h"
  33. #include "bm.h"
  34. #include "color.h"
  35.  
  36. #if !defined(_lint)
  37. static char rcsid[] OPTIONAL = "$Id: bmutil.c,v 1.40 1997/08/19 01:19:22 root Exp root $";
  38. #endif
  39.  
  40. #ifndef UNIX
  41. #define        SETVBUF
  42. #else
  43. #include <sys/stat.h>
  44. #endif
  45.  
  46.  
  47. #ifdef SETVBUF
  48. #define        MYBUF    1024
  49. #endif
  50.  
  51. static void readareas (const char *name);
  52. void freeareas (void);
  53. static int is_area2 (const char *name);
  54.  
  55. extern int mbx_data (struct mbx * m, struct list * cclist, char *extra, int returnreceipt);
  56. extern int dombroute (int argc, char *argv[], void *p);
  57. extern void updateCtl (const char *who, struct let * info);
  58. extern int makeBBSbid (char *bid, int bidlen, char *line);
  59.  
  60. #ifdef SAMCALLB
  61. extern char *cb_lookname (char *);
  62. #endif
  63.  
  64. #ifdef MAILCMDS
  65. char Badmsg[] = "Invalid Message number %d\n";
  66. static char Badrange[] = "Invalid Message range '%d - %d'\n";
  67. char Nomail[] = "No messages\n";
  68. static char NoMsgs[] = "No message numbers given\n";
  69. static char anymore[] = "More(N=no)? ";
  70. static int readnotes (struct mbx * m, int already);
  71. static long isnewmail (struct mbx * m);
  72. static int initnotes (struct mbx * m);
  73. static void noteheader (struct mbx * m, int usebid);
  74. static void close_notes (int a, void *b, void *c);
  75. static void mfclose (struct mbx * m);
  76. #endif
  77.  
  78. int lockit (struct mbx * m);
  79. extern char *nntp_name_expansion (char *name);
  80. static void dodeleting (struct mbx * m, int msg);
  81. static int is_area (const char *name, const char *listfile);
  82. char *mblookname (struct mbx * m, char *str);
  83. void notifynewmail (struct mbx * m);
  84. void backEmUp (int len);
  85. #ifdef SAMCALLB
  86. void leadingCaps (char *str, int others);
  87. #endif
  88.  
  89. static char logdelmsg[] = "Msg %d in area '%s' made %s by '%s'";
  90.  
  91. const char hitEnter[] = "Hit enter to continue";
  92.  
  93. extern int MBnoReturnReceipt;
  94.  
  95.  
  96. FILE *subdir_fopen (char *name, const char *mode);
  97.  
  98. FILE *
  99. subdir_fopen (char *name, const char *mode)
  100. {
  101. FILE *fp;
  102. char *cp;
  103.  
  104. #undef ENOENT
  105. #define ENOENT 2
  106.  
  107.     if ((fp = fopen (name, mode)) != (FILE *) 0)
  108.         return fp;
  109.     if ((errno == ENOENT) && !strchr (mode, 'r')) {
  110.         cp = &name[1];
  111.         while ((cp = strpbrk (cp, "/\\")) != (char *) 0) {
  112.             *cp = 0;
  113.             if (access (name, 0))
  114.                 if (mkdir (name, 0777))
  115.                     return ((FILE *) 0);
  116.             *cp++ = '/';
  117.         }
  118.         fp = fopen (name, mode);
  119.         return fp;    /* NULL if STILL not opened */
  120.     }
  121.     return ((FILE *) 0);
  122. }
  123.  
  124.  
  125.  
  126. #ifdef MAILBOX
  127. #ifdef MAILCMDS
  128.  
  129. static int
  130. initnotes (struct mbx *m)
  131. {
  132. char buf[256];
  133. int wasit = 0;
  134. #ifdef USERLOG
  135. register struct let *cmsg;
  136. int i;
  137. #endif
  138.  
  139.     if (m->mfile != NULLFILE) {
  140.         (void) fclose (m->mfile);
  141.         wasit = m->nmsgs;
  142.     }
  143.     sprintf (buf, "%s/%s.txt", Mailspool, m->area);
  144.     if ((m->mfile = subdir_fopen (buf, READ_TEXT)) == NULLFILE)
  145.         return 0;
  146.     m->mboxsize = (long) filelength (fileno (m->mfile));
  147.     if (!(m->sid & MBX_SID) && !stricmp (m->area, m->name))    /* our private mail area */
  148.         m->mysize = m->mboxsize;
  149.     m->nmsgs = 0;
  150.     m->change &= CHG_SPECIAL;
  151.     m->newmsgs = 0;
  152.     m->newmsgsonentry = 0;
  153.     m->anyread = 0;
  154.     /* Allocate space for reading messages */
  155.     (void) readnotes (m, wasit);
  156. #ifdef USERLOG
  157.     m->current = 0;        /*reset it*/
  158.     if (m->nmsgs)
  159.         for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
  160.             if ((cmsg->status & BM_READ) == 0) {
  161.                 m->current = i;    /* first new message */
  162.                 break;
  163.             }
  164.     /* start at one if no new messages */
  165.     if ((m->current == 0) && m->nmsgs)
  166.         m->current++;
  167. #endif
  168.     return 0;
  169. }
  170.  
  171.  
  172.  
  173. /* readnotes assumes that ifile is pointing to the first
  174.  * message that needs to be read.  For initial reads of a
  175.  * notesfile, this will be the beginning of the file.  For
  176.  * rereads when new mail arrives, it will be the first new
  177.  * message.
  178.  */
  179. static int
  180. readnotes (register struct mbx *m, int already)
  181. {
  182. register FILE *fp;
  183. char mailbox[128];
  184. long size;
  185. register int i, isit;
  186. register struct let *cmsg;
  187. struct let *new;
  188.  
  189.     m->newmsgs = m->hmsgs = 0;
  190.     sprintf (mailbox, "%s/control/%s.ctl", Mailspool, m->area);
  191.     if ((fp = subdir_fopen (mailbox, READ_BINARY)) != NULLFILE) {
  192. #if !defined(TNOS_68K)
  193.         m->stdoutbuf = mallocw (MYBUF);
  194.         (void) setvbuf (fp, m->stdoutbuf, _IOFBF, MYBUF);
  195. #endif
  196.         size = (long) filelength (fileno (fp));
  197.         new = (struct let *) mallocw ((unsigned long) size + sizeof (struct let));
  198.  
  199.         (void) fread (&new[1], (unsigned) size, 1, fp);
  200.         (void) fclose (fp);
  201.         if (already && !strcmp (m->area, m->name))
  202.             memcpy (new, m->mbox, (unsigned) (already + 1) * sizeof (struct let));
  203.  
  204. #if !defined(TNOS_68K)
  205.         free (m->stdoutbuf);
  206.         m->stdoutbuf = 0;
  207. #endif
  208.         free (m->mbox);
  209.         m->mbox = new;
  210.         m->nmsgs = (int) (size / (long) sizeof (struct let));
  211.  
  212.         isit = issysarea (m->area);
  213.         for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
  214.             if (isit) {
  215.                 if ((cmsg->bid > m->lastread) && !(cmsg->status & BM_DELETE))
  216.                     m->newmsgs++;
  217.                 else
  218.                     cmsg->status |= BM_READ;
  219.                 if (cmsg->status & BM_ONHOLD)
  220.                     m->hmsgs++;
  221.             } else {
  222.                 if (!(cmsg->status & BM_READ))
  223.                     m->newmsgs++;
  224.                 if (cmsg->status & BM_ONHOLD)
  225.                     m->hmsgs++;
  226.             }
  227.     } else
  228.         m->nmsgs = 0;
  229.  
  230.     m->newmsgsonentry = m->newmsgs;
  231.     return 0;
  232. }
  233.  
  234.  
  235.  
  236. /* Display the header to a listing */
  237. static void
  238. noteheader (struct mbx *m, int usebid)
  239. {
  240. char *area, *cp;
  241.  
  242.     area = strdup (m->area);
  243.     while ((cp = strchr (area, '/')) != NULLCHAR)
  244.         *cp = '.';
  245.     bbscolorcls (m);
  246.     tputs ("\nMail area: ");
  247.     bbscolorchange (m, "09");
  248.     tputs (area);
  249.     bbscolorchange (m, "0B");
  250.     tprintf ("  %d ", m->nmsgs);
  251.     bbscolorchange (m, "0F");
  252.     tprintf ("message%s -  ", m->nmsgs == 1 ? " " : "s ");
  253.     bbscolorchange (m, "0B");
  254.     tprintf ("%d ", m->newmsgs);
  255.     bbscolorchange (m, "0F");
  256.     tprintf ("new\n\nStat  #        TO         FROM %s SUBJECT\n", (usebid) ? "MESSAGE ID   " : " DATE    SIZE");
  257.     free (area);
  258. }
  259.  
  260.  
  261.  
  262. /* list headers of a notesfile a message */
  263. /* Rearranged display - WG7J */
  264. int
  265. dolistnotes (int argc, char *argv[], void *p)
  266. {
  267. struct mbx *m;
  268. struct let *cmsg;
  269. char *cp, *s;
  270. char smtp_date[SLINELEN], smtp_from[SLINELEN];
  271. char smtp_subject[SLINELEN], tstring[LINELEN], type;
  272. char smtp_to[SLINELEN], smtp_bid[30];
  273. int start, stop;
  274. long size;
  275. int c, usemore = 0, lin;
  276. int usebid = 0;
  277. int headerseen = 0;
  278. #if 0
  279. char *area;
  280. #endif
  281. #ifdef USERLOG
  282. long msgid;
  283. #endif
  284.  
  285.     m = (struct mbx *) p;
  286.  
  287.     /*If this user doesn't have read-permissions,
  288.      *we're not going to let him list anything - WG7J    */
  289.     if (m->privs & NO_READCMD) {
  290.         tputs (Noperm);
  291.         return 0;
  292.     }
  293.     if (m->mfile == NULLFILE) {
  294.         if (!(m->privs & ALL_AREAS))
  295.             tputs (Nomail);
  296.         return 0;
  297.     }
  298.     if (m->stype == 'B') {
  299.         usebid = 1;
  300.         m->stype = ' ';
  301.     }
  302.     if (m->stype == '$')
  303.         usebid = 1;
  304.  
  305.     if ((m->stype == 'S' || m->stype == '$' || m->stype == '>' || m->stype == '<') && argc == 1) {
  306.         tputs ("Search criterium needed!\n");
  307.         return 0;
  308.     }
  309.     if ((lin = m->morerows) != 0)
  310.         usemore = 1;    /* Display More prompt */
  311.  
  312. #if 0
  313.     noteheader (m, usebid);
  314. #endif
  315.  
  316.     stop = m->nmsgs;
  317.     if (m->stype == 'L') {    /* LL (List Latest) command */
  318.         if (argc > 1)
  319.             start = stop - atoi (argv[1]) + 1;
  320.         else
  321.             start = stop;
  322.         if (start < 1)
  323.             start = 1;
  324.     } else {
  325.         if ((m->stype == 'A') || (m->stype == '>') ||
  326.             (m->stype == '<') || (m->stype == 'S') ||
  327.             (m->stype == '$') || (m->stype == 'H') ||
  328.             (m->stype == 'M')) {
  329.             start = 1;
  330.             stop = m->nmsgs;
  331.         } else {
  332.             if (argc > 1)
  333.                 start = atoi (argv[1]);
  334.             else
  335. #ifdef USERLOG
  336. #if 0
  337.                 start = m->nmsgs - m->newmsgsonentry + 1;
  338. #else
  339.                 start = (m->newmsgsonentry) ? m->current : (m->nmsgs - m->newmsgsonentry + 1);
  340. #endif
  341. #else
  342.                 start = 1;
  343. #endif
  344.             if (argc > 2)
  345.                 stop = atoi (argv[2]);
  346.         }
  347.     }
  348.     if (stop > m->nmsgs)
  349.         stop = m->nmsgs;
  350.     if (start < 1 || start > stop) {
  351.         if (!(m->privs & ALL_AREAS)) {
  352.             if ((m->stype == ' ') || (m->stype == 'M'))
  353.                 tputs ("No new mail.\n");
  354.             else
  355.                 tputs ("Invalid range.\n");
  356.         }
  357.         return 0;
  358.     }
  359.     if (m->sid & MBX_HTTP)
  360.         tprintf ("<PRE>\n");
  361.     for (cmsg = &m->mbox[start]; start <= stop; start++, cmsg++) {
  362.         *smtp_date = '\0';
  363.         *smtp_from = '\0';
  364.         *smtp_subject = '\0';
  365.         *smtp_to = '\0';
  366.         *smtp_bid = '\0';
  367.         type = ' ';
  368.         fseek (m->mfile, cmsg->start, 0);
  369.         size = cmsg->size;
  370.         /* Be a little less selfish - WG7J */
  371.         kwait (NULL);
  372.  
  373. #ifdef USERLOG
  374.         /* We need to get the id from the last message listed !
  375.          * m->mbox[i].start (ie cmsg->start) points to the 'From ' line
  376.          * next are the 'Received....' and 'ID...' lines
  377.          * These are thes line added by our smtp server.
  378.          * following the 'AA' is the number that we want ! - WG7J
  379.          */
  380. #if 0
  381.         if (start == stop) {
  382. #endif
  383.             /*The 'From ' line*/
  384.             (void) fgets (tstring, sizeof (tstring), m->mfile);
  385.             size -= (long) strlen (tstring);
  386.             /*The 'Received' line*/
  387.             (void) fgets (tstring, sizeof (tstring), m->mfile);
  388.             size -= (long) strlen (tstring);
  389.             /*The 'ID' line*/
  390.             (void) fgets (tstring, sizeof (tstring), m->mfile);
  391.             size -= (long) strlen (tstring);
  392.             /* find id number */
  393. #ifdef nope
  394.             if ((cmsg->bid > m->lastread) && (cmsg->bid > m->newlastread))
  395.                 m->newlastread = cmsg->bid;
  396. #else
  397.             if ((cp = strstr (tstring, "AA")) != NULLCHAR) {
  398.                 /*what follows is the message-number*/
  399.                 msgid = atol (cp + 2);
  400.                 if ((msgid > m->lastread) && (msgid > m->newlastread))
  401.                     m->newlastread = msgid;
  402.             }
  403. #endif
  404. #if 0
  405.         }
  406. #endif
  407. #endif
  408.  
  409.         while (size > 0 && fgets (tstring, sizeof (tstring), m->mfile) != NULLCHAR) {
  410.             kwait (NULL);
  411.             if (*tstring == '\n')    /* end of header */
  412.                 break;
  413.             size -= (long) strlen (tstring);
  414.             rip (tstring);
  415.             /* handle continuation later */
  416.             if (*tstring == ' ' || *tstring == '\t')
  417.                 continue;
  418.             switch (htype (tstring)) {
  419.                 case FROM:
  420.                     cp = getaddress (tstring, 0);
  421.                     strncpy (smtp_from, cp != NULLCHAR ? cp : "", 8);
  422.                     if ((cp = strchr (smtp_from, '@')) != NULLCHAR)
  423.                         *cp = '\0';    /* get rid of @-host or @-bbs field */
  424.                     break;
  425.                 case SUBJECT:
  426.                     trimright (tstring);
  427.                     cp = skipwhite (&tstring[9]);
  428.                     strncpy (smtp_subject, cp, 35);
  429.                     break;
  430.                 case MSGID:
  431.                     strncpy (smtp_bid, &tstring[12], 29);
  432.                     break;
  433.                 case DATE:
  434.                     if ((cp = strchr (tstring, ',')) == NULLCHAR)
  435.                         cp = &tstring[6];
  436.                     else
  437.                         cp++;
  438.                     /* skip spaces */
  439.                     while (*cp == ' ')
  440.                         cp++;
  441.                     if (strlen (cp) < 17)
  442.                         break;    /* not a valid length */
  443.                     s = smtp_date;
  444.                     /* copy day */
  445.                     if (atoi (cp) < 10 && *cp != '0')
  446.                         *s++ = ' ';
  447.                     else
  448.                         *s++ = *cp++;
  449.                     *s++ = *cp++;
  450.  
  451.                     *s++ = ' ';
  452.                     *s = '\0';
  453.                     while (*cp == ' ')
  454.                         cp++;
  455.                     strncat (s, cp, 3);    /* copy month */
  456. #ifdef use_time
  457.                     cp += 3;
  458.                     while (*cp == ' ')
  459.                         cp++;
  460.                     /* skip year */
  461.                     while (isdigit (*cp))
  462.                         cp++;
  463.                     /* copy time */
  464.                     strncat (s, cp, 6);    /* space hour : min */
  465. #endif
  466.                     break;
  467.                 case BBSTYPE:
  468.                     type = tstring[16];
  469.                     break;
  470.                 case TO:
  471.                     strncpy (smtp_to, &tstring[4], 13);
  472.                     break;
  473.                 case NOHEADER:
  474.                 default:
  475.                     break;
  476.             }
  477.         }
  478.         if ((m->stype == 'M') && (cmsg->status & BM_READ))
  479.             continue;
  480.         if (m->stype == ' ' || m->stype == 'L' || m->stype == 'M' ||
  481.          m->stype == 'A' || (type == m->stype && m->stype != ' ') ||
  482.             ((m->stype == 'H') && (cmsg->status & BM_ONHOLD)) ||
  483.             ((m->stype == 'S') && (strstr (strlwr (smtp_subject), argv[1]) != NULLCHAR)) ||
  484.             ((m->stype == '<') && (strstr (strlwr (smtp_from), argv[1]) != NULLCHAR)) ||
  485.             ((m->stype == '$') && (strstr (strlwr (smtp_bid), argv[1]) != NULLCHAR)) ||
  486.             ((m->stype == '>') && (strstr (strlwr (smtp_to), argv[1]) != NULLCHAR))) {
  487.             lin--;
  488.             if ((cmsg->status & BM_DELETE) && !(m->privs & SYSOP_CMD))
  489.                 strcpy (smtp_subject, "[DELETED]");
  490.             if (!(headerseen++ % 50))
  491.                 noteheader (m, usebid);
  492.             bbscolorchange (m, "07");
  493.             if (m->sid & MBX_HTTP)
  494.                 tprintf ("<A HREF=\"/bbs/message/%s/%d.html\">", m->area, start);
  495.             tprintf ("%c%c%c%c%3d ", (start == m->current ? '>' : ' '),
  496.                  (cmsg->status & BM_DELETE ? 'D' :
  497.                   cmsg->status & BM_ONHOLD ? 'H' : ' '),
  498.                  (cmsg->status & BM_READ ? 'Y' : 'N'),
  499.                  (cmsg->status & BM_PERMANENT) ? 'P' : ' ',
  500.                  start);
  501.             bbscolorchange (m, "0E");
  502.             tprintf ("%13.13s ", smtp_to);
  503.             bbscolorchange (m, "0C");
  504.             tprintf ("%8.8s ", smtp_from);
  505.             bbscolorchange (m, "07");
  506.             if (usebid) {
  507.                 char *tmpbid, *bidptr = smtp_bid;
  508.  
  509.                 if (*bidptr == '<')
  510.                     bidptr++;
  511.                 if ((tmpbid = strchr (bidptr, '@')) != NULLCHAR) {
  512.                     if (strstr (tmpbid, ".bbs") || strcmp (tmpbid, "@hamradio"))
  513.                         *tmpbid++ = 0;
  514.                     else {
  515.                         *tmpbid = '_';
  516.                         tmpbid = strchr (tmpbid, '.');
  517.                         if (tmpbid)
  518.                             *tmpbid = 0;
  519.                     }
  520.                 }
  521.                 (void) strupr (bidptr);
  522.                 tprintf ("%-13.13s ", bidptr);
  523.             } else {
  524.                 tprintf ("%-7.7s ", smtp_date);
  525.                 tprintf ("%5ld ", cmsg->size);
  526.             }
  527.             bbscolorchange (m, "0E");
  528.             tprintf ("%.34s\n", smtp_subject);
  529.             if (m->sid & MBX_HTTP)
  530.                 tprintf ("</A>");
  531. #ifdef STATS_AREA
  532.             STATS_addarea (0, 1, m->area);
  533. #endif
  534.         }
  535.         /* More prompting added - WG7J */
  536.         if (usemore && lin == 0) {
  537.             if (m->type == TELNET || m->type == TIP)
  538.                 c = tkeywait ("--More--", 0, m->linemode);
  539.             else    /* For AX.25 and NET/ROM connects - WG7J */
  540.                 c = mykeywait (anymore, m);
  541. #ifdef MBXTDISC
  542.             start_timer (&m->tdisc);
  543. #endif
  544.             if (c == -1 || c == 'q' || c == 'Q' || c == 'n' || c == 'N')
  545.                 break;
  546. #ifdef TNOS_68K
  547.             if (c == '\l' || c == '\r')
  548. #else
  549.             if (c == '\n' || c == '\r')
  550. #endif
  551.                 lin = 1;
  552.             else
  553.                 lin = m->morerows;
  554.  
  555.         }
  556.     }
  557.     if (m->sid & MBX_HTTP)
  558.         tprintf ("</PRE>\n");
  559.     return 0;
  560. }
  561.  
  562.  
  563.  
  564. /*  save msg on stream - if noheader set don't output the header */
  565. int
  566. msgtofile (
  567. struct mbx *m,
  568. int msg,
  569. FILE * tfile,    /* already open for write */
  570. int noheader,
  571. int numbered
  572. ) {
  573. char tstring[LINELEN];
  574. long size;
  575. int lineno = 0;
  576.  
  577.     if (m->mfile == NULLFILE) {
  578.         tputs (Nomail);
  579.         return -1;
  580.     }
  581.     fseek (m->mfile, m->mbox[msg].start, 0);
  582.     size = m->mbox[msg].size;
  583.  
  584.     if (noheader) {
  585.         /* skip header */
  586.         while (size > 0 && fgets (tstring, sizeof (tstring) - 1, m->mfile) != NULLCHAR) {
  587.             size -= (long) strlen (tstring);
  588.             kwait (NULL);
  589.             if (*tstring == '\n')
  590.                 break;
  591.         }
  592.     }
  593.     while (size > 0 && fgets (tstring, sizeof (tstring) - 1, m->mfile)
  594.            != NULLCHAR) {
  595.         kwait (NULL);
  596.         size -= (long) strlen (tstring);
  597.         if (numbered)
  598.             fprintf (tfile, "%02d) ", ++lineno);
  599.         fputs (tstring, tfile);
  600.         if (ferror (tfile)) {
  601.             tputs ("Error writing mail file\n");
  602.             return -1;
  603.         }
  604.     }
  605.  
  606.     return 0;
  607. }
  608.  
  609.  
  610.  
  611. static void
  612. dodeleting (struct mbx *m, int msg)
  613. {
  614.     switch (m->stype) {
  615.         case 'U':
  616.             m->mbox[msg].status &= ~BM_DELETE;
  617.             tprintf ("Msg %d Un-Killed.\n", msg);
  618.             break;
  619.         case 'A':
  620.             m->mbox[msg].status &= ~BM_ONHOLD;
  621.             tprintf ("Msg %d Available.\n", msg);
  622.             log (m->user, logdelmsg, msg, m->area, "available", m->name);
  623.             break;
  624.         case 'H':
  625.             m->mbox[msg].status |= BM_ONHOLD;
  626.             tprintf ("Msg %d Held.\n", msg);
  627.             log (m->user, logdelmsg, msg, m->area, "held", m->name);
  628.             break;
  629.         case 'T':
  630.             m->mbox[msg].status &= ~BM_PERMANENT;
  631.             tprintf ("Msg %d Temporary.\n", msg);
  632.             log (m->user, logdelmsg, msg, m->area, "temporary", m->name);
  633.             break;
  634.         case 'P':
  635.             m->mbox[msg].status |= BM_PERMANENT;
  636.             tprintf ("Msg %d Permanent.\n", msg);
  637.             log (m->user, logdelmsg, msg, m->area, "permanent", m->name);
  638.             break;
  639.         default:
  640.             if (m->mbox[msg].status & BM_PERMANENT)
  641.                 tprintf ("Can't kill message %d - Message is permanent!\n", msg);
  642.             else {
  643.                 m->mbox[msg].status |= BM_DELETE;
  644.                 m->mbox[msg].status &= ~BM_ONHOLD;
  645.                 tprintf ("Msg %d Killed.\n", msg);
  646.                 if (!issysarea (m->area))
  647.                     m->change |= CHG_DELETE;
  648.             }
  649.             break;
  650.     }
  651.     statusCtl (m->area, "ctl", &m->mbox[msg], msg, 0);
  652. }
  653.  
  654.  
  655.  
  656. /* dodelmsg - delete message in current notesfile */
  657. /* Modified to allow the 'KM' command. 920307 -  WG7J */
  658. /* also handles holsing/releasing messages - KO4KS */
  659. int
  660. dodelmsg (int argc, char *argv[], void *p)
  661. {
  662. struct mbx *m;
  663. int msg = 0, i = 0;
  664. char *myargv[NARG];
  665. int myargc = 0;
  666. int maxmsg;
  667. struct let *cmsg;
  668. char *tmpbuf;
  669. int start, end;
  670.  
  671.     m = (struct mbx *) p;
  672.  
  673.     /* If this user doesn't have read-permissions,
  674.      * we're not going to let him kill/hold anything;
  675.      * allow anyone to kill/hold messages in areas
  676.      * who's names start with 'nts' - WG7J
  677.      */
  678.     /* Check if we have permission to delete others mail */
  679.     if ((m->privs & NO_READCMD) || (m->privs & NO_SENDCMD) ||
  680.         (!(m->privs & FTP_WRITE) &&
  681.          stricmp (m->area, m->name) &&
  682.          strnicmp (m->area, "nts", 3))) {
  683.         tputs (Noperm);
  684.         return 0;
  685.     }
  686.     if ((m->stype == 'A' || m->stype == 'H' || m->stype == 'P' || m->stype == 'T') && !(m->privs & SYSOP_CMD)) {
  687.         tputs (Noperm);
  688.         return 0;
  689.     }
  690.     if (m->stype == 'S') {
  691.         if (argc > 2) {
  692.             myargc = msg = atoi (argv[1]);
  693.             i = atoi (argv[2]);
  694.         }
  695.         if ((argc < 3) || !msg || !i)
  696.             tputs (NoMsgs);
  697.         else {
  698.             for (; myargc <= i; myargc++) {
  699.                 m->mbox[myargc].status |= BM_DELETE;
  700.                 m->mbox[myargc].status &= ~BM_ONHOLD;
  701.                 statusCtl (m->area, "ctl", &m->mbox[myargc], myargc, 0);
  702.             }
  703.             if (!issysarea (m->area))
  704.                 m->change |= CHG_DELETE;
  705.             tprintf ("Msgs %d to %d Killed.\n", msg, i);
  706.         }
  707.         return 0;
  708.     }
  709.     if (m->mfile == NULLFILE) {
  710.         tputs (Nomail);
  711.         return 0;
  712.     }
  713.     /*If this is the KM command, setup myargv[]
  714.      *to contain up to NARG message numbers - WG7J
  715.      */
  716.     if (m->stype == 'M') {
  717.         myargc = 1;
  718.         /* scan all messsages to find read ones */
  719.         maxmsg = min (m->nmsgs, NARG - 1);
  720.         for (i = 1; i <= maxmsg; i++) {
  721.             cmsg = &m->mbox[i];
  722.             if (cmsg->status & BM_READ) {    /*found a read msg!*/
  723.                 tmpbuf = mallocw (18);    /*allocate space for the new argument*/
  724.                 myargv[myargc++] = itoa (i, tmpbuf, 10);
  725.             }
  726.         }
  727.         if (myargc == 1) {
  728.             tputs (NoMsgs);
  729.             return 0;
  730.         }
  731.         argc = myargc;
  732.     } else {
  733.         if (argc == 1) {
  734.             if (m->stype != 'A') {
  735.                 msg = m->current;
  736.                 dodeleting (m, msg);
  737.                 return 0;
  738.             } else {
  739.                 for (i = 1; i <= m->nmsgs; i++) {
  740.                     cmsg = &m->mbox[i];
  741.                     if (cmsg->status & BM_ONHOLD) {
  742.                         cmsg->status &= ~BM_ONHOLD;
  743.                         statusCtl (m->area, "ctl", cmsg, i, 0);
  744.                     }
  745.                 }
  746.                 tputs ("All Messages Available.\n");
  747.                 return 0;
  748.             }
  749.         }
  750.         /*simply point to the old arguments*/
  751.         for (i = 1; i < argc; i++)
  752.             myargv[i] = argv[i];
  753.     }
  754.  
  755.     /* See if x - y format was used and use a for i = x to y loop */
  756.     if (argc > 2 && myargv[2][0] == '-') {        /*lint !e644 */
  757.         start = atoi (myargv[1]);
  758.         if (myargv[2][1])
  759.             end = atoi (&myargv[2][1]);
  760.         else
  761.             end = atoi (myargv[3]);
  762.         if (start < 0 || start > m->nmsgs || end < 0 || end > m->nmsgs)
  763.             tprintf (Badrange, start, end);
  764.         else
  765.             for (i = start; i <= end; i++) {
  766.                 msg = i;
  767.                 dodeleting (m, msg);
  768.             }    /* endfor */
  769.     } else
  770.         for (i = 1; i < argc; ++i) {
  771.             tmpbuf = strchr (myargv[i], '-');    /* N5KNX: allow from-to msg specification */
  772.             msg = atoi (myargv[i]);
  773.             if (tmpbuf == NULLCHAR)
  774.                 maxmsg = msg;
  775.             else
  776.                 maxmsg = atoi (++tmpbuf);
  777.             if (maxmsg < msg) {
  778.                 tprintf (Badmsg, myargv[i]);
  779.                 continue;
  780.             }
  781.             for (; msg <= maxmsg; msg++) {
  782.                 if (msg < 0 || msg > m->nmsgs) {
  783.                     tprintf (Badmsg, msg);
  784.                     continue;
  785.                 }
  786.                 dodeleting (m, msg);
  787.             }
  788.         }
  789.     /* If this was 'KM'
  790.      * free the memory allocated for myargv[] - WG7J
  791.      */
  792.     if (m->stype == 'M') {
  793.         for (i = 1; i < argc; i++)
  794.             free (myargv[i]);
  795.     }
  796.     return 0;
  797. }
  798.  
  799.  
  800.  
  801. struct clparms {
  802.     int nostatus, nodelete;
  803.     long *hostsize;
  804.     long _hostsize;
  805.     char name[20];        /* Name of remote station */
  806.     char area[64];        /* name of current mail area */
  807.     FILE *mfile;        /* mail data file pointer */
  808.     struct let *mbox;
  809.     int nmsgs;        /* number of messages in this mail box */
  810.     int isbbs;
  811. };
  812.  
  813.  
  814. static void
  815. close_notes (int a OPTIONAL, void *b, void *c OPTIONAL)
  816. {
  817. struct clparms *cl;
  818. struct let *cmsg;
  819. char *line;
  820. char tstring[LINELEN], buf[256];
  821. char buf2[256];
  822. long size, diff;
  823. FILE *nfile;
  824. int i, nextisBID, numwritten = 0;
  825. int foundstatus, firstIDline;
  826. #if 0
  827. char *cp;
  828. long msgid;
  829. #endif
  830.  
  831.     cl = (struct clparms *) b;
  832.     line = tstring;
  833.     sprintf (buf, "%s/control/%s.ctl", Mailspool, cl->area);
  834.     (void) remove (buf);
  835.  
  836.     (void) fclose (cl->mfile);
  837.     sprintf (buf, "%s/%s.txt", Mailspool, cl->area);
  838.     sprintf (buf2, "%s/%s.bak", Mailspool, cl->area);
  839.     (void) remove (buf2);    /* delete it here, just in case! */
  840.     (void) rename (buf, buf2);
  841.     if ((cl->mfile = subdir_fopen (buf2, READ_TEXT)) == NULLFILE) {
  842.         rmlock (Mailspool, cl->area);
  843.         free (cl);
  844.         return;
  845.     }
  846.     if ((nfile = subdir_fopen (buf, WRITE_TEXT)) == NULLFILE) {
  847.         (void) fclose (cl->mfile);
  848.         rmlock (Mailspool, cl->area);
  849.         free (cl);
  850.         return;
  851.     }
  852.     /* copy tmp file back to notes file */
  853.     for (cmsg = &cl->mbox[1], i = 1; i <= cl->nmsgs; i++, cmsg++) {
  854.         fseek (cl->mfile, cmsg->start, 0);
  855.         kwait (NULL);
  856.         cmsg->start = ftell (nfile);
  857.         size = cmsg->size;
  858.         diff = 0;
  859.         foundstatus = 0;
  860.         /* It is not possible to delete messages if nodelete is set */
  861.         if ((cmsg->status & BM_DELETE) && !cl->nodelete)
  862.             continue;
  863.         nextisBID = 0;
  864.         firstIDline = 0;
  865.         /* copy the header */
  866.         while (size > 0 && fgets (line, LINELEN, cl->mfile) != NULLCHAR) {
  867.             kwait (NULL);    /* can cause problems if exiting NOS */
  868. #if 0
  869.             if (!firstIDline && nextisBID && (cp = strstr (line, "AA")) != NULLCHAR) {
  870.                 /*what follows is the message-number*/
  871.                 msgid = atol (cp + 2);
  872. #else
  873.             if (!firstIDline && nextisBID && strstr (line, "AA") != NULLCHAR) {
  874. #endif
  875.                 nextisBID = 0;
  876.                 firstIDline = 1;
  877.             }
  878.             if (!strncmp (line, Hdrs[RECEIVED], strlen (Hdrs[RECEIVED])))
  879.                 nextisBID = 1;
  880.             if (!strncmp (line, Hdrs[STATUS], strlen (Hdrs[STATUS])))
  881.                 foundstatus = 1;
  882.             size -= (long) strlen (line);
  883.             if (*line == '\n') {
  884. #ifdef notagain
  885.                 if (cmsg->status & BM_FORWARDED) {
  886.                     fprintf (nfile, "%s%s\n", Hdrs[XFORWARD],
  887.                          cl->name);
  888.                     diff += (strlen (Hdrs[XFORWARD]) + strlen (cl->name) + 1);
  889.                 }
  890. #endif
  891.                 if (!foundstatus && (cmsg->status & BM_READ) != 0 && !cl->nostatus) {
  892.                     fprintf (nfile, "%sR\n", Hdrs[STATUS]);
  893.                     diff += (long) (strlen (Hdrs[STATUS]) + 2);
  894.                 }
  895.                 fprintf (nfile, "\n");
  896.                 break;
  897.             }
  898.             fputs (line, nfile);
  899.             kwait (NULL);    /* can cause problems if exiting NOS */
  900.         }
  901.         kwait (NULL);
  902.         while (size > 0 && fgets (line, LINELEN, cl->mfile) != NULLCHAR) {
  903.             kwait (NULL);    /* can cause problems if exiting NOS */
  904.             if (!cl->nostatus && !strncmp (line, Hdrs[RRECEIPT], strlen (Hdrs[RRECEIPT]))
  905.                 && !strcmp (cl->name, cl->area) && (cmsg->status & BM_RRECEIPT)) {
  906.                 fputs ("Return-Receipt-Sent\n", nfile);
  907.                 diff -= (long) strlen (line);
  908.                 diff += 20;
  909.             } else
  910.                 fputs (line, nfile);
  911.             size -= (long) strlen (line);
  912.             kwait (NULL);    /* dont want no damaged files */
  913.             if (ferror (nfile)) {
  914.                 (void) fclose (nfile);
  915.                 (void) fclose (cl->mfile);
  916.                 rmlock (Mailspool, cl->area);
  917.                 free (cl);
  918.                 return;
  919.             }
  920.         }
  921.         cmsg->status &= BM_READ;
  922.         cmsg->size += diff;
  923.         updateCtl (cl->area, cmsg);
  924.         (void) fflush (nfile);
  925.         numwritten++;
  926.     }
  927.     if (!cl->isbbs && !stricmp (cl->name, cl->area))
  928.         *cl->hostsize = ftell (nfile);    /* Update the size of our hosts' mailbox */
  929.     /* potientially dangerous! */
  930.     /* remove a zero length file */
  931.     if (!numwritten) {
  932.         (void) fclose (nfile);
  933.         (void) unlink (buf);
  934.     } else
  935.         (void) fclose (nfile);
  936.     (void) fclose (cl->mfile);
  937.     (void) remove (buf2);    /* leave it around, for now! NOT! */
  938.     rmlock (Mailspool, cl->area);
  939.     free (cl->mbox);
  940.     free (cl);
  941.     kwait (NULL);
  942.     return;
  943. }
  944.  
  945.  
  946.  
  947. /* close the temp file while coping mail back to the mailbox */
  948. int
  949. closenotes (struct mbx *m, int exiting)
  950. {
  951. int nostatus, nodelete = 0;
  952. struct clparms *cl;
  953.  
  954.     if (m->mfile == NULLFILE || !*m->area)
  955.         return 0;
  956.     nostatus = issysarea (m->area);
  957.  
  958.     /* Allow any user to delete from area names starting with 'nts' */
  959.     if (!strnicmp (m->area, "nts", 3))
  960.         nostatus = 0;
  961.     if (!(m->change & CHG_NORMAL) || nostatus) {    /* no changes were made (or bulletin) */
  962.         mfclose (m);
  963.         m->mboxsize = 0;
  964.         return 0;
  965.     }
  966.     /* If this area is not our own private message area, then we will not add a
  967.      * Status line to indicate that the message has been read.
  968.      */
  969.     if (strcmp (m->area, m->name)) {
  970.         nostatus = 1;
  971.         /* Don't delete messages from public message areas unless you are
  972.          * a SYSOP.
  973.          */
  974.         nodelete = !(m->privs & SYSOP_CMD);
  975.     }
  976.     /* Allow any user to delete from area names starting with 'nts' */
  977.     if (!strnicmp (m->area, "nts", 3))
  978.         nodelete = 0;
  979.     /* If not a SYSOP, not an "nts" area, not our area, AND deletions, must be BBS forward */
  980.     if (m->change & CHG_DELETE) {
  981.         nodelete = 0;
  982.         log (-1, "PBBS forwarding rewrite of personal area '%s' by %s ", m->area, m->name);
  983.     }
  984.     if (nostatus && nodelete) {
  985.         mfclose (m);
  986.         m->mboxsize = 0;
  987.         return 0;
  988.     }
  989.     scanmail (m);
  990.     if (lockit (m))
  991.         return -1;
  992.     cl = (struct clparms *) mallocw (sizeof (struct clparms));
  993.  
  994.     cl->nodelete = nodelete;
  995.     cl->nostatus = nostatus;
  996.     if (!exiting)
  997.         cl->hostsize = &m->mysize;
  998.     else    {
  999.         cl->_hostsize = m->mysize;
  1000.         cl->hostsize = &cl->_hostsize;
  1001.     }
  1002.     cl->isbbs = (m->sid & MBX_SID);
  1003.     strncpy (cl->name, m->name, 20);
  1004.     strncpy (cl->area, m->area, 64);
  1005.     cl->mfile = m->mfile;
  1006.     cl->nmsgs = m->nmsgs;
  1007.     cl->mbox = m->mbox;
  1008.     (void) newproc ("Closing notefile", 2560, close_notes, 0, cl, 0, 0);
  1009.     kwait (NULL);
  1010.     m->mfile = NULLFILE;
  1011.     m->mbox = (struct let *) 0;
  1012.     mfclose (m);
  1013.     m->mboxsize = 0;
  1014.     return 0;
  1015. }
  1016.  
  1017. #endif /* MAILCMDS */
  1018.  
  1019.  
  1020.  
  1021. /* Returns 1 if name is in the given area file, 0 otherwise */
  1022. static int
  1023. is_area (const char *name, const char *listfile)
  1024. {
  1025. char buf[LINELEN], *cp;
  1026. FILE *fp;
  1027.  
  1028.     if ((fp = fopen (listfile, READ_TEXT)) == NULLFILE)
  1029.         return 0;
  1030.     while (fgets (buf, sizeof (buf), fp) != NULLCHAR) {
  1031.         /* The first word on each line is all that matters */
  1032.         if (isalnum (buf[0])) {    /* skip comments */
  1033.             if ((cp = strpbrk (buf, " \t\n")) != NULLCHAR)
  1034.                 *cp = '\0';
  1035.             (void) nntp_name_expansion (buf);
  1036.             if (stricmp (name, buf) == 0) {    /* found it */
  1037.                 (void) fclose (fp);
  1038.                 return 1;
  1039.             }
  1040.         }
  1041.     }
  1042.     (void) fclose (fp);
  1043.     return 0;
  1044. }
  1045.  
  1046.  
  1047.  
  1048. /* Returns 1 if name is a public message Area, 0 otherwise */
  1049. int
  1050. isarea (const char *name)
  1051. {
  1052.     return (is_area2 (name));
  1053. }
  1054.  
  1055.  
  1056.  
  1057. /* Returns 1 if name is a public message Area, 0 otherwise */
  1058. int
  1059. issysarea (const char *name)
  1060. {
  1061.     return (is_area (name, AreaSlist));
  1062. }
  1063.  
  1064.  
  1065.  
  1066. #ifdef MAILCMDS
  1067. int
  1068. lockit (struct mbx *m)
  1069. {
  1070. int c, cnt = 0;
  1071.  
  1072.     while (mlock (Mailspool, m->area)) {
  1073.         (void) kpause (1000L);    /* Wait one second */
  1074.         if (++cnt == 10) {
  1075.             char buf[80];
  1076.  
  1077.             sprintf (buf, "Mail file '%s' is busy, Abort or *Retry ? ", m->area);
  1078.             cnt = 0;
  1079.             c = tkeywait (buf, 1, m->linemode);
  1080.             if (c == 'A' || c == 'a' || c == EOF) {
  1081.                 mfclose (m);
  1082.                 return 1;
  1083.             }
  1084.         }
  1085.     }
  1086.     return 0;
  1087. }
  1088.  
  1089.  
  1090.  
  1091. /* read the next message or the current one if new */
  1092. int
  1093. doreadnext (int argc OPTIONAL, char *argv[]OPTIONAL, void *p)
  1094. {
  1095. struct mbx *m;
  1096. char buf[14], *newargv[2], buf2[6];
  1097.  
  1098.     m = (struct mbx *) p;
  1099.     if (m->mfile == NULLFILE)
  1100.         return 0;
  1101.     if ((m->mbox[m->current].status & BM_READ) != 0) {
  1102.         if (m->current == 1 && m->anyread == 0)
  1103.             ;
  1104.         else if (m->current < m->nmsgs)
  1105.             m->current++;
  1106.         else {
  1107.             tputs ("Last message\n");
  1108.             return 0;
  1109.         }
  1110.     }
  1111.     sprintf (buf, "%d", m->current);
  1112.     strcpy (buf2, "read");
  1113.     newargv[0] = buf2;
  1114.     newargv[1] = buf;
  1115.     return doreadmsg (2, newargv, p);
  1116. }
  1117.  
  1118. #endif
  1119.  
  1120.  
  1121.  
  1122. #ifdef SAMCALLB
  1123. void
  1124. leadingCaps (char *str, int others)
  1125. {
  1126. char *cp;
  1127.  
  1128.     cp = str;
  1129.     (void) strlwr (cp);
  1130.     if (!others) {
  1131.         if ((cp = strchr (cp, ' ')) != 0)
  1132.             (void) strupr (cp);
  1133.         return;
  1134.     }
  1135.     do {
  1136.         cp = strchr (cp, ' ');
  1137.         if (cp != NULL) {
  1138.             cp = skipwhite (cp);
  1139.             *cp = (char) toupper (*cp);
  1140.         }
  1141.     } while (cp);
  1142. }
  1143. #endif
  1144.  
  1145.  
  1146. char *
  1147. mblookname (struct mbx *m, char *str)
  1148. {
  1149.     if ((m != NULLMBX) && (m->realname) && (*m->realname == '(') && (m->realname[1] != ')'))
  1150.         return (strdup (m->realname));
  1151.  
  1152.     if (strchr (str, '('))
  1153.         return (0);    /* already has a name */
  1154. #ifdef SAMCALLB
  1155.     return (cb_lookname (str));
  1156. #else
  1157.     return (0);
  1158. #endif
  1159. }
  1160.  
  1161.  
  1162.  
  1163. #ifdef MAILCMDS
  1164.  
  1165. extern int MbRead;
  1166.  
  1167. /* display message on the crt given msg number */
  1168. /* Modified to allow the 'RM' command, 920307 - WG7J */
  1169. int
  1170. doreadmsg (int argc, char *argv[], void *p)
  1171. {
  1172. struct mbx *m;
  1173. register int c, col, lin;
  1174. unsigned char buf[MAXBUF + 2], *cp, *cp2;
  1175. char *subj = 0, *theto = 0;
  1176. int msg, cnt, i, usemore = 0, verbose, mbxheader, pathcol = 5;
  1177. int header, lastheader;
  1178. long size;
  1179. char *myargv[NARG];
  1180. int myargc;
  1181. int maxmsg;
  1182. struct let *cmsg;
  1183. char *tmpbuf;
  1184. char *returnreceipt;
  1185. #ifdef USERLOG
  1186. long msgid;
  1187. #endif
  1188.  
  1189.     m = (struct mbx *) p;
  1190.  
  1191.     /*Check for read-permissions - WG7J */
  1192.     if (m->privs & NO_READCMD) {
  1193.         tputs (Noperm);
  1194.         return 0;
  1195.     }
  1196. #ifdef MBFWD
  1197.     if (m->stype == 'O')
  1198.         return (dombroute (argc, argv, p));
  1199. #endif
  1200.     if ((m->mfile == NULLFILE) || (m->nmsgs == 0)) {
  1201.         if (!(m->privs & ALL_AREAS))
  1202.             tputs (Nomail);
  1203.         return 0;
  1204.     }
  1205.     if ((lin = m->morerows) != 0)
  1206.         usemore = 1;    /* Display More prompt */
  1207.  
  1208.     /*If this is the RM or VM command, setup myargv[]
  1209.      *to contain up to NARG message numbers - WG7J
  1210.      */
  1211.     if (m->stype == 'M') {
  1212.         myargc = 1;
  1213.         if (!m->newmsgs) {
  1214.             tputs (Nomail);
  1215.             return 0;
  1216.         }
  1217.         /* scan all messsages to find unread ones */
  1218.         maxmsg = min (m->nmsgs, m->current + NARG - 2);
  1219.         for (i = m->current; i <= maxmsg; i++) {
  1220.             cmsg = &m->mbox[i];
  1221.             if (!(cmsg->status & BM_READ)) {    /*found an unread msg!*/
  1222.                 tmpbuf = mallocw (18);    /*allocate space for the new argument*/
  1223.                 myargv[myargc++] = itoa (i, tmpbuf, 10);
  1224.             }
  1225.         }
  1226.         argc = myargc;
  1227.     } else {
  1228.         /*simply point to the old arguments*/
  1229.         for (i = 1; i < argc; i++)
  1230.             myargv[i] = argv[i];
  1231.     }
  1232.     if (argc == 1) {
  1233.         tputs ("Usage: Read/Verbose #\n");
  1234.         return 0;
  1235.     }
  1236.     m->state = MBX_READ;
  1237.     for (i = 1; i < argc; ++i) {
  1238.         msg = atoi (myargv[i]);        /*lint !e644 */
  1239.         if (msg < 1 || msg > m->nmsgs) {
  1240.             if (!(m->privs & ALL_AREAS))
  1241.                 tprintf (Badmsg, msg);
  1242.             goto iamdone;
  1243.         }
  1244.         MbRead++;
  1245.         fseek (m->mfile, m->mbox[msg].start, 0);
  1246. #ifdef USERLOG
  1247.         /* Check the ID number of this message and
  1248.          * adjust new lastread count, if needed - WG7J
  1249.          */
  1250.         (void) fgets ((char *) buf, MAXBUF + 2, m->mfile);    /* the 'From ' line */
  1251.         (void) fgets ((char *) buf, MAXBUF + 2, m->mfile);    /* the 'Received: ' line */
  1252.         (void) fgets ((char *) buf, MAXBUF + 2, m->mfile);    /* the ' ID' line */
  1253.         /* find id number */
  1254.         if ((cp = (unsigned char *) strstr ((char *) buf, "AA")) != (unsigned char *) 0) {
  1255.             /*what follows is the message-number*/
  1256.             msgid = atol ((char *) cp + 2);
  1257.             if ((msgid > m->lastread) && (msgid > m->newlastread))
  1258.                 m->newlastread = msgid;
  1259.         }
  1260.         fseek (m->mfile, m->mbox[msg].start, 0);
  1261. #endif
  1262. #ifdef nope            /* was USERLOG */
  1263.         if ((m->mbox[msg].bid > m->lastread) && (m->mbox[msg].bid > m->newlastread))
  1264.             m->newlastread = m->mbox[msg].bid;
  1265. #endif
  1266.  
  1267.         m->anyread = 1;
  1268.         returnreceipt = 0;
  1269.         size = m->mbox[msg].size;
  1270.         m->current = msg;
  1271.         header = NOHEADER;
  1272.         mbxheader = 0;
  1273.         if ((*argv[0] == 'v') || (m->stype == 'H'))
  1274.             verbose = 1;    /* display all header lines */
  1275.         else
  1276.             verbose = 0;
  1277.  
  1278.         m->inmessage = 1;
  1279.         if (m->stype != 'M')
  1280.             bbscolorcls (m);
  1281.         bbscolorchange (m, "07");
  1282.         if (m->sid & MBX_HTTP)
  1283.             tprintf ("<PRE>\n");
  1284.         tprintf ("Message #%d %s\n", msg,
  1285.              m->mbox[msg].status & BM_ONHOLD ? "[On Hold - Awaiting Review of SYSOP]" :
  1286.              m->mbox[msg].status & BM_DELETE ? "[Deleted]" : "");
  1287.  
  1288.         if ((m->mbox[msg].status & (BM_ONHOLD | BM_DELETE)) && !(m->privs & SYSOP_CMD))
  1289.             continue;
  1290.  
  1291.         /* When you have sysop privs,
  1292.              * only mark your own private area as read and changed.
  1293.              * other areas, only mark as read, NOT changed !
  1294.              * for regular users, simply mark all as read and changed.
  1295.              * That way sysops can read other's mail without
  1296.              * marking stuff read that really wasn't read by
  1297.              * the right person !
  1298.              * for regular users, simply mark as read.
  1299.              * 910312 - WG7J
  1300.              */
  1301.         if (!(m->mbox[msg].status & BM_READ)) {
  1302.             m->mbox[msg].status |= BM_READ;
  1303.             /* regular users */
  1304.             if (!issysarea (m->area) && (!(m->privs & SYSOP_CMD) || ((m->privs & SYSOP_CMD) && !strcmp (m->name, m->area))))    /*sysops*/
  1305.                 m->change |= CHG_READ;
  1306.             m->newmsgs--;
  1307.         }
  1308.         --lin;
  1309.         col = 0;
  1310.         while (!feof (m->mfile) && size > 0) {
  1311.             for (col = 0; col < MAXBUF;) {
  1312.                 c = getc (m->mfile);
  1313.                 size--;
  1314.                 if (feof (m->mfile) || size == 0)    /* end this line */
  1315.                     break;
  1316.                 if (c == '\t') {
  1317.                     cnt = col + 8 - (col & 7);
  1318.                     if (cnt >= MAXBUF)    /* end this line */
  1319.                         break;
  1320.                     while (col < cnt)
  1321.                         buf[col++] = ' ';
  1322.                 } else {
  1323.                     if (c == '\n')
  1324.                         break;
  1325.                     buf[col++] = uchar (c);
  1326.                 }
  1327.             }
  1328.             if (col < MAXBUF)
  1329.                 buf[col++] = '\n';
  1330.             buf[col] = '\0';
  1331.             if (mbxheader > 0) {
  1332.                 /* Digest R: lines and display as a Path: line */
  1333.                 if (strnicmp ((char *) buf, "R:", 2) != 0 || (cp = (unsigned char *) strchr ((char *) buf, '@')) == (unsigned char *) 0) {
  1334.                     tputc ('\n');
  1335.                     bbscolorchange (m, "0B");
  1336.                     mbxheader = -1;    /* don't get here again */
  1337.                     verbose = 1;
  1338.                 } else {
  1339.                     if (*(++cp) == ':')
  1340.                         ++cp;
  1341.                     for (cp2 = cp; isalnum (*cp2); ++cp2)
  1342.                         ;
  1343.                     *cp2 = '\0';
  1344.                     if (mbxheader++ == 1) {
  1345.                         bbscolorchange (m, "07");
  1346.                         tputs (Hdrs[PATH]);
  1347.                         pathcol = 5;
  1348.                         --lin;
  1349.                     } else {
  1350.                         tputc ('!');
  1351.                         if (++pathcol + (int) strlen ((char *) cp) > MAXCOL - 3) {
  1352.                             tputs ("\n      ");
  1353.                             pathcol = 5;
  1354.                             --lin;
  1355.                         }
  1356.                     }
  1357.                     tputs ((char *) cp);
  1358.                     pathcol += (int) strlen ((char *) cp);
  1359.                     ++lin;    /* to allow for not printing it later */
  1360.                 }
  1361.             }
  1362.             if (col == 1 && !mbxheader) {
  1363.                 bbscolorchange (m, "0B");
  1364.                 /* last header line reached */
  1365.                 if (!verbose)
  1366.                     mbxheader = 1;
  1367.             }
  1368.             if (verbose)
  1369.                 /*                tputs (buf);    */
  1370.                 (void) colorprintf (NULLCHAR, m->usecolor, buf);
  1371.             if (!strncmp (Hdrs[RRECEIPT], (char *) buf, strlen (Hdrs[RRECEIPT])))
  1372.                 returnreceipt = strdup ((char *) &buf[strlen (Hdrs[RRECEIPT])]);
  1373.             if (!verbose && !mbxheader) {
  1374.                 lastheader = header;
  1375.                 if (!isspace (*buf))
  1376.                     header = htype ((char *) buf);
  1377.                 else
  1378.                     header = lastheader;
  1379.                 switch (header) {
  1380.                     case SUBJECT:
  1381.                         subj = strdup ((char *) &buf[strlen (Hdrs[SUBJECT]) - 4]);
  1382.                         tputs ((char *) buf);
  1383.                         break;
  1384.                     case MSGID:
  1385. #ifdef MBFWD
  1386.                         /* give a "traditional BBS" version to the user */
  1387.                         {
  1388.                             char bid[LINELEN];
  1389.  
  1390.                             (void) makeBBSbid (bid, sizeof (bid), (char *) buf);
  1391.                             (void) strupr (bid);
  1392.                             tprintf ("%s%s\n", Hdrs[MSGID], bid);
  1393.                         }
  1394.                         break;
  1395. #endif
  1396.                     case TO:
  1397.                         theto = strdup ((char *) &buf[strlen (Hdrs[TO])]);
  1398.                         /* fall through */
  1399.                     case FROM:
  1400.                         {
  1401.                             char *nm;
  1402.  
  1403.                             rip ((char *) buf);
  1404.                             tputs ((char *) buf);
  1405.                             nm = strchr ((char *) buf, ' ');
  1406.                             if (nm && (nm = mblookname (NULLMBX, ++nm)) != 0) {
  1407.                                 tputs (nm);
  1408.                                 free (nm);
  1409.                             }
  1410.                             tputc ('\n');
  1411.                         }
  1412.                         break;
  1413.                     case CC:
  1414.                     case DATE:
  1415.                     case REPLYTO:
  1416.                     case APPARTO:
  1417.                     case ERRORSTO:
  1418.                     case XMAILGROUP:
  1419.                     case ORGANIZATION:
  1420.                         tputs ((char *) buf);
  1421.                         break;
  1422.                     case XBBSHOLD:
  1423.                         if (m->privs & SYSOP_CMD)
  1424.                             tputs ((char *) buf);
  1425.                         break;
  1426.                     default:
  1427.                         ++lin;
  1428.                 }
  1429.             }
  1430.             col = 0;
  1431.             if (usemore && --lin <= 0) {
  1432.                 if (m->type == TELNET || m->type == TIP)
  1433.                     c = tkeywait ("--More--", 0, m->linemode);
  1434.                 else    /* For AX.25 and NET/ROM connects - WG7J */
  1435.                     c = mykeywait (anymore, m);
  1436. #ifdef MBXTDISC
  1437.                 start_timer (&m->tdisc);
  1438. #endif
  1439.                 lin = m->morerows;
  1440.                 if (c == -1 || c == 'q' || c == 'Q')
  1441.                     break;
  1442. #ifdef TNOS_68K
  1443.                 if (c == '\l' || c == '\r')
  1444. #else
  1445.                 if (c == '\n' || c == '\r')
  1446. #endif
  1447.                     lin = 1;
  1448.             }
  1449.         }        /* while !eof */
  1450. #ifdef TUTOR
  1451.         {
  1452.             char savbuf[MBXLINE + 1];
  1453.  
  1454.             memcpy (savbuf, m->line, MBXLINE + 1);
  1455.             sprintf (m->line, "msgend %d", msg);
  1456.             mbscripthook (m, "msgend.sys");
  1457.             memcpy (m->line, savbuf, MBXLINE + 1);
  1458.         }
  1459. #endif
  1460.         if (returnreceipt && !MBnoReturnReceipt && !(m->mbox[msg].status & BM_RRECEIPT)) {
  1461.             struct mbx *mm;
  1462.  
  1463.             m->mbox[msg].status |= BM_RRECEIPT;
  1464.             rip (returnreceipt);    /* strip off <CR> */
  1465.             tprintf ("[Sending return receipt to '%s']\n", returnreceipt);
  1466.             mm = (struct mbx *) mallocw (sizeof (struct mbx));
  1467.  
  1468.             mm->tomsgid = mm->date = mm->origbbs = mm->tofrom = NULLCHAR;
  1469.             mm->origto = returnreceipt;
  1470.             if (!subj)
  1471.                 subj = strdup ("    No subject");
  1472.             mm->subject = subj;
  1473.             mm->realname = strdup ("()");
  1474.             rip (subj);    /* strip off <CR> */
  1475.             subj[0] = subj[1] = 'R';
  1476.             subj[2] = ':';
  1477.             subj[3] = ' ';
  1478.             mm->stype = 'P';
  1479.             strncpy (mm->name, m->name, 20);
  1480.             if ((mm->tfile = tmpfile ()) != NULLFILE) {
  1481.                 struct list *cclist = NULLLIST;
  1482.                 char fullfrom[MBXLINE];
  1483.  
  1484.                 (void) addlist (&cclist, returnreceipt, 0, returnreceipt);
  1485.                 sprintf (fullfrom, "%s@%s", m->name, Hostname);
  1486.                 (void) mbx_data (mm, NULLLIST, NULLCHAR, 0);
  1487.                 if (!theto)
  1488.                     theto = strdup ("unknown addressee");
  1489.                 rip (theto);    /* strip off the <CR> */
  1490.                 fprintf (mm->tfile, "Message received - Originally addressed to: '%s'\n", theto);
  1491.                 fseek (mm->tfile, 0L, 0);    /* rewind file */
  1492.                 (void) queuejob (mm->tfile, Hostname, cclist, fullfrom);
  1493.                 (void) fclose (mm->tfile);
  1494.                 del_list (cclist);
  1495.                 smtptick (NULL);    /* wake up SMTP to send mail */
  1496.             }
  1497.             free (mm->realname);
  1498.             free (mm);
  1499.             free (returnreceipt);
  1500.         }
  1501.         free (subj);
  1502.         free (theto);
  1503.         m->inmessage = 0;
  1504. #ifdef STATS_AREA
  1505.         STATS_addarea (1, 1, m->area);
  1506. #endif
  1507.     }            /* for argc */
  1508.       iamdone:
  1509.     /* If this was 'RM' or 'VM',
  1510.      * free the memory allocated for myargv[] - WG7J
  1511.      */
  1512.     if (m->stype == 'M') {
  1513.         for (i = 1; i < argc; i++)
  1514.             free (myargv[i]);
  1515.     }
  1516.     if (m->sid & MBX_HTTP)
  1517.         tprintf ("</PRE>\n");
  1518.     return 0;
  1519. }
  1520.  
  1521.  
  1522.  
  1523. /* Set up m->to when replying to a message. The subject is returned in
  1524.  * m->line.
  1525.  */
  1526. int
  1527. mbx_reply (
  1528. int argc,
  1529. char *argv[],
  1530. struct mbx *m,
  1531. struct list **cclist,    /* Pointer to buffer for pointers to cc recipients */
  1532. char **rhdr    /* Pointer to buffer for extra reply headers */
  1533. ) {
  1534. char subject[MBXLINE], *msgid = NULLCHAR, *date = NULLCHAR;
  1535. char *cp;
  1536. int msg, lastheader, header = NOHEADER, k;
  1537. long size;
  1538.  
  1539.     /* Free anything that might be allocated
  1540.      * since the last call to mbx_to() or mbx_reply()
  1541.      */
  1542.     free (m->to);
  1543.     m->to = NULLCHAR;
  1544.     free (m->tofrom);
  1545.     m->tofrom = NULLCHAR;
  1546.     free (m->tomsgid);
  1547.     m->tomsgid = NULLCHAR;
  1548.     free (m->origto);
  1549.     m->origto = NULLCHAR;
  1550.     subject[0] = '\0';
  1551.  
  1552.     if (argc == 1)
  1553.         msg = m->current;
  1554.     else
  1555.         msg = atoi (argv[1]);
  1556.     if (m->mfile == NULLFILE) {
  1557.         if (m->sid & MBX_SID)
  1558.             tputs ("NO - ");
  1559.         tputs (Nomail);
  1560.         return 0;
  1561.     }
  1562.     if (msg < 1 || msg > m->nmsgs) {
  1563.         if (m->sid & MBX_SID)
  1564.             tputs ("NO - ");
  1565.         tprintf (Badmsg, msg);
  1566.         return -1;
  1567.     }
  1568.     fseek (m->mfile, m->mbox[msg].start, 0);
  1569.     size = m->mbox[msg].size;
  1570.     m->current = msg;
  1571.     while (size > 0 && fgets (m->line, MBXLINE - 1, m->mfile) != NULLCHAR) {
  1572.         size -= (long) strlen (m->line);
  1573.         if (m->line[0] == '\n')    /* end of header */
  1574.             break;
  1575.         rip (m->line);
  1576.         lastheader = header;
  1577.         if (!isspace (m->line[0])) {
  1578.             header = htype (m->line);
  1579.             lastheader = NOHEADER;
  1580.         }
  1581.         switch (header) {
  1582.             case SUBJECT:
  1583.                 trimright (m->line);
  1584.                 if (strlen (m->line) > 11 && !strnicmp (&m->line[9], "Re:", 3))
  1585.                     strncpy (subject, &m->line[9], MBXLINE);
  1586.                 else    {
  1587.                     strcpy (subject, "Re: ");
  1588.                     strncpy (&subject[4], &m->line[9], MBXLINE - 4);
  1589.                 }
  1590.                 break;
  1591.             case FROM:
  1592.                 trimright (m->line);
  1593.                 if (m->to == NULLCHAR && (cp = getaddress (m->line, 0)) !=
  1594.                     NULLCHAR)
  1595.                     m->to = strdup (cp);
  1596.                 break;
  1597.             case REPLYTO:
  1598.                 if ((cp = getaddress (m->line, 0)) != NULLCHAR) {
  1599.                     free (m->to);
  1600.                     m->to = strdup (cp);
  1601.                 }
  1602.                 break;
  1603.             case MSGID:
  1604.                 trimright (m->line);
  1605.                 free (msgid);
  1606.                 msgid = strdup (&m->line[12]);
  1607.                 break;
  1608.             case DATE:
  1609.                 free (date);
  1610.                 date = strdup (&m->line[6]);
  1611.                 break;
  1612. #ifdef notdef
  1613.                 /* don't want a reply back to myself - WG7J */
  1614.             case TO:
  1615.             case APPARTO:
  1616. #endif
  1617.             case CC:
  1618.                 /* Get addresses on To, Cc and Apparently-To lines */
  1619.                 cp = m->line;
  1620.                 k = (int) (strlen (cp) + 1);
  1621.                 m->line[min(k, MBXLINE)] = '\0';    /* add extra null at end */
  1622.                 for (;;) {
  1623.                     if ((cp = getaddress (cp, lastheader == header || cp != m->line)) == NULLCHAR)
  1624.                         break;
  1625.                     (void) addlist (cclist, cp, 0, cp);
  1626.                     /* skip to next address, if any */
  1627.                     cp += strlen (cp) + 1;
  1628.                 }
  1629.                 break;
  1630.             default:
  1631.                 break;
  1632.         }
  1633.     }
  1634.     if (msgid != NULLCHAR || date != NULLCHAR) {
  1635.         *rhdr = mallocw (LINELEN);
  1636.         sprintf (*rhdr, "In-Reply-To: your message ");
  1637.         if (date != NULLCHAR) {
  1638.             sprintf (m->line, "of %s.\n", date);
  1639.             strcat (*rhdr, m->line);
  1640.             if (msgid != NULLCHAR)
  1641.                 strcat (*rhdr, "             ");
  1642.         }
  1643.         if (msgid != NULLCHAR) {
  1644.             sprintf (m->line, "%s\n", msgid);
  1645.             strcat (*rhdr, m->line);
  1646.         }
  1647.         free (msgid);
  1648.         free (date);
  1649.     }
  1650.     strncpy (m->line, subject, MBXLINE);
  1651.     return 0;
  1652. }
  1653.  
  1654.  
  1655.  
  1656. #ifdef USERLOG
  1657.  
  1658. /*get the last message listed/read
  1659.  *from the areaname.USR file
  1660.  *keeps track for each user.
  1661.  *February '92, WG7J
  1662.  */
  1663. void
  1664. getlastread (struct mbx *m)
  1665. {
  1666. FILE *Alog;
  1667. char buf[256];
  1668. char *cp;
  1669. int found = 0;
  1670.  
  1671.     m->lastread = m->newlastread = 0L;
  1672.  
  1673.     sprintf (buf, "%s/users/%s.usr", Mailspool, m->area);
  1674.     if ((Alog = subdir_fopen (buf, "r+")) == NULLFILE) {
  1675.         /* USR file doesn't exist, create it */
  1676.         if ((Alog = subdir_fopen (buf, "w")) == NULLFILE)
  1677.             return;
  1678.         /* Add this user as first one */
  1679.         sprintf (buf, "%s 0\n", m->name);
  1680.         fputs (buf, Alog);
  1681.         (void) fclose (Alog);
  1682.         return;
  1683.     }
  1684.     /*Find user in the usr file for this area*/
  1685.     for (;;) {
  1686.         if (fgets (buf, sizeof (buf), Alog) == NULLCHAR)
  1687.             break;
  1688.         if ((cp = strchr (buf, ' ')) != NULLCHAR)    {
  1689.             *cp = '\0';
  1690.             if (!stricmp (m->name, buf)) {
  1691.                 /*found user*/
  1692.                 cp++;
  1693.                 while (*cp == ' ')    /*skip blanks*/
  1694.                     cp++;
  1695.                 m->lastread = atol (cp);
  1696.                 found = 1;
  1697.                 break;
  1698.             }
  1699.         }
  1700.     }
  1701.     if (!found) {
  1702.         /*Add user*/
  1703.         sprintf (buf, "%s 0\n", m->name);
  1704.         fputs (buf, Alog);
  1705.     }
  1706.     (void) fclose (Alog);
  1707.     return;
  1708. }
  1709.  
  1710.  
  1711.  
  1712. /* Write the new last read id number to the USR file - WG7J
  1713.  * only update if this is not a bbs,
  1714.  * current area is a public area and not 'help',
  1715.  * or anything that starts with 'sys',
  1716.  * and a new message was actually listed/read
  1717.  */
  1718. void
  1719. setlastread (struct mbx *m)
  1720. {
  1721. FILE *Alog, *tfile;
  1722. char buf[256];
  1723. char tmpname[80];
  1724. char *cp;
  1725. int doit = 0;
  1726.  
  1727.     if ((m->sid & MBX_SID) || (m->newlastread <= m->lastread))
  1728.         return;
  1729.  
  1730.     /*    if(issysarea(m->area))
  1731.         if ((m->privs & MBX_SYSOP) || (stricmp(m->area, "help")))
  1732.             doit = 1;    */
  1733.     if (isarea (m->area) && strcmp (m->area, "help"))
  1734.         doit = 1;
  1735.     if ((m->privs & SYSOP_CMD) && issysarea (m->area))
  1736.         doit = 1;
  1737.  
  1738.     if (doit) {
  1739.  
  1740. #ifdef notdef
  1741.         tprintf ("SETLAST: %d\n", m->newlastread);
  1742. #endif
  1743.  
  1744.  
  1745.         sprintf (buf, "%s/users/%s.usr", Mailspool, m->area);
  1746.  
  1747.         /* Rename the USR file to a tempfile */
  1748. #ifdef UNIX
  1749.         strncpy (tmpname, buf, 75);
  1750.         strcat (tmpname, ".bak");
  1751. #else
  1752.         (void) tmpnam (tmpname);
  1753. #endif
  1754.         if (rename (buf, tmpname))
  1755.             /* Can't rename ??? */
  1756.             return;
  1757.  
  1758.         if ((Alog = subdir_fopen (buf, "w")) == NULLFILE) {
  1759.             /* can't creat new USR file ???*/
  1760.             (void) rename (tmpname, buf);    /* try to undo the damage */
  1761.             return;
  1762.         }
  1763.         if ((tfile = subdir_fopen (tmpname, "r")) == NULLFILE)
  1764.             /* can't open renamed file ??? */
  1765.             return;
  1766.  
  1767.         /*Write all users back, but update this one!*/
  1768.         while (fgets (buf, sizeof (buf), tfile) != NULLCHAR) {
  1769.             if ((cp = strchr (buf, ' ')) != NULLCHAR)
  1770.                 *cp = '\0';
  1771.             if (!stricmp (m->name, buf)) {
  1772.                 /*found this user*/
  1773.                 sprintf (buf, "%s %lu\n", m->name, m->newlastread);
  1774.             } else if (cp)
  1775.                 *cp = ' ';    /* restore the space !*/
  1776.             fputs (buf, Alog);
  1777.         }
  1778.         (void) fclose (tfile);
  1779.         unlink (tmpname);
  1780.         (void) fclose (Alog);
  1781.     }
  1782.     return;
  1783. }
  1784.  
  1785. #endif /*USERLOG*/
  1786.  
  1787.  
  1788.  
  1789. void
  1790. scanmail (struct mbx *m)
  1791. {                /* Get any new mail */
  1792.     if (!isnewmail (m))
  1793.         return;
  1794.     if (lockit (m))
  1795.         return;
  1796.     (void) initnotes (m);
  1797.     rmlock (Mailspool, m->area);
  1798. }
  1799.  
  1800.  
  1801.  
  1802. /* Check the current mailbox to see if new mail has arrived.
  1803.  * Returns the difference in size.
  1804.  */
  1805. static long
  1806. isnewmail (struct mbx *m)
  1807. {
  1808. char buf[256];
  1809.  
  1810.     sprintf (buf, "%s/%s.txt", Mailspool, m->area);
  1811.     return fsize (buf) - m->mboxsize;
  1812. }
  1813.  
  1814.  
  1815.  
  1816. /* Check if the private mail area has changed */
  1817. long
  1818. isnewprivmail (struct mbx *m, const char *ext)
  1819. {
  1820. long cnt;
  1821. char buf[256];
  1822.  
  1823.     sprintf (buf, "%s/%s.%s", Mailspool, m->name, ext);
  1824.     cnt = m->mysize;
  1825.     m->mysize = fsize (buf);
  1826.     return m->mysize - cnt;    /* != 0 not more than once */
  1827. }
  1828.  
  1829.  
  1830.  
  1831. void
  1832. notifynewmail (struct mbx *m)
  1833. {                /* not a BBS, but from within ANY area */
  1834.     if (!(m->sid & MBX_SID) && (isnewprivmail (m, "txt") > 0L)) {
  1835.         tprintf ("\007You have new mail in your personal area (%s). Please Kill when read!\n", m->name);
  1836.         usflush (Curproc->output);
  1837.     }
  1838. }
  1839.  
  1840. #endif
  1841. #endif
  1842.  
  1843.  
  1844.  
  1845. /* This function returns the length of a file. The proper thing would be
  1846.  * to use stat(), but it fails when using DesqView together with Turbo-C
  1847.  * code.
  1848.  */
  1849. long
  1850. fsize (char *name)
  1851. {
  1852. long cnt;
  1853. FILE *fp;
  1854.  
  1855.     if ((fp = subdir_fopen (name, READ_TEXT)) == NULLFILE)
  1856.         return -1L;
  1857.     fseek (fp, 0L, 2);
  1858.     cnt = ftell (fp);
  1859.     /*    cnt = filelength (fileno(fp)); */
  1860.     (void) fclose (fp);
  1861.     return cnt;
  1862. }
  1863.  
  1864.  
  1865.  
  1866. #ifdef MAILCMDS
  1867. /* close the temporary mail file */
  1868. static void
  1869. mfclose (struct mbx *m)
  1870. {
  1871.     if (m->mfile != NULLFILE)
  1872.         (void) fclose (m->mfile);
  1873.     m->mfile = NULLFILE;
  1874. #ifdef SETVBUF
  1875.     free (m->stdoutbuf);
  1876.     m->stdoutbuf = NULLCHAR;
  1877. #endif
  1878. }
  1879.  
  1880. #endif
  1881.  
  1882.  
  1883.  
  1884. /* erase a previous prompt via backspaces */
  1885. void
  1886. backEmUp (int len)
  1887. {
  1888. int i;
  1889.  
  1890.     /* Get rid of the prompt */
  1891.     for (i = len; i != 0; i--)
  1892.         tputc ('\b');
  1893.     for (i = len; i != 0; i--)
  1894.         tputc (' ');
  1895.     for (i = len; i != 0; i--)
  1896.         tputc ('\b');
  1897.     tflush ();
  1898. }
  1899.  
  1900.  
  1901.  
  1902. /* Print prompt and read one character, telnet version */
  1903. int
  1904. tkeywait (
  1905. const char *prompt,    /* Optional prompt */
  1906. int flush,    /* Flush queued input? */
  1907. int linemode    /* Negotiate line mode? */
  1908. ) {
  1909. int c, cl, oldimode, oldomode;
  1910.  
  1911.     if (flush && socklen (Curproc->input, 0) != 0)
  1912.         (void) recv_mbuf (Curproc->input, NULL, 0, NULLCHAR, 0);    /* flush */
  1913.     if (prompt == NULLCHAR)
  1914.         prompt = hitEnter;
  1915.     tprintf ("%s", prompt);
  1916.     /* hack - handle Unix telnet clients correctly */
  1917.     if (linemode)
  1918.         tprintf ("%c%c%c%c%c%c%c", IAC, SB, TN_LINEMODE, 1, 2, IAC, SE);
  1919.     tprintf ("%c%c%c", IAC, WILL, TN_ECHO);
  1920.     usflush (Curproc->output);
  1921.  
  1922.     /* discard the response */
  1923.  
  1924.     oldimode = sockmode (Curproc->input, SOCK_BINARY);
  1925.     oldomode = sockmode (Curproc->output, SOCK_BINARY);
  1926.  
  1927.     while ((c = rrecvchar (Curproc->input)) == IAC) {
  1928.         c = rrecvchar (Curproc->input);
  1929.         if (c == SB) {
  1930.             if ((c = rrecvchar (Curproc->input)) == EOF)
  1931.                 break;
  1932.             cl = c;
  1933.             c = rrecvchar (Curproc->input);
  1934.             while ((c != EOF) && !(cl == IAC && c == SE)) {
  1935.                 cl = c;
  1936.                 c = rrecvchar (Curproc->input);
  1937.             }
  1938.         } else if (c > 250 && c < 255)
  1939.             (void) rrecvchar (Curproc->input);
  1940.     }
  1941.  
  1942.     (void) sockmode (Curproc->output, oldomode);
  1943.     (void) sockmode (Curproc->input, oldimode);
  1944.  
  1945.     backEmUp ((int) strlen (prompt));
  1946.     tprintf ("%c%c%c", IAC, WONT, TN_ECHO);
  1947.     if (linemode)
  1948.         tprintf ("%c%c%c%c%c%c%c", IAC, SB, TN_LINEMODE, 1, 1, IAC, SE);
  1949.     usflush (Curproc->output);
  1950.     return c;
  1951. }
  1952.  
  1953.  
  1954.  
  1955. /* Print -more- prompt and read reply,
  1956.  * AX.25 and NETROM version - WG7J
  1957.  * <CR> is taken as a 'Yes'
  1958.  */
  1959. int
  1960. mykeywait (char *prompt, struct mbx *m)
  1961. {
  1962.     tputs (prompt);
  1963.     usflush (Curproc->output);
  1964.     if (recvline (m->user, (unsigned char *) m->line, MBXLINE) == -1) {
  1965.         return -1;
  1966.     }
  1967.     /* Only 'N' or 'n' really matters */
  1968.     if ((*m->line == 'N') || (*m->line == 'n'))
  1969.         return -1;
  1970.     return 0;
  1971. }
  1972.  
  1973.  
  1974.  
  1975. struct areas {
  1976.     struct areas *next;
  1977.     char *name;
  1978. };
  1979. static struct areas *Areas = NULL;
  1980.  
  1981.  
  1982.  
  1983. static void
  1984. readareas (const char *name)
  1985. {
  1986. FILE *fp;
  1987. struct areas *ca = (struct areas *) 0, *na;
  1988. char *cp, buf[FILE_PATH_SIZE];
  1989.  
  1990.     if ((fp = fopen (name, READ_TEXT)) == NULL)
  1991.         return;
  1992.  
  1993.     while (fgets (buf, sizeof (buf), fp) != NULL) {
  1994.         if (buf[0] == '#' || buf[0] == '-')    /* comment line */
  1995.             continue;
  1996.         cp = buf;
  1997.         /* get first token on line */
  1998.         while (*cp) {
  1999.             if (*cp == '\n' || *cp == ' ' || *cp == '\t') {
  2000.                 *cp = '\0';
  2001.                 break;
  2002.             }
  2003.             cp++;
  2004.         }
  2005.         if (*buf) {
  2006.             na = (struct areas *) mallocw (sizeof (struct areas));
  2007.  
  2008.             na->name = strdup (buf);
  2009.             na->next = NULL;
  2010.             if (Areas == NULL)
  2011.                 Areas = na;
  2012.             else if (ca)
  2013.                 ca->next = na;
  2014.             ca = na;
  2015.         }
  2016.     }
  2017.     (void) fclose (fp);
  2018. }
  2019.  
  2020.  
  2021.  
  2022. static int
  2023. is_area2 (const char *name)
  2024. {
  2025. #ifdef MAILCMDS
  2026. struct areas *a;
  2027.  
  2028.     if (!Areas)
  2029.         readareas (Arealist);
  2030.  
  2031.     a = Areas;
  2032.  
  2033.     while (a) {
  2034.         if (stricmp (a->name, name) == 0)
  2035.             return 1;
  2036.         a = a->next;
  2037.     }
  2038. #endif
  2039.     return 0;
  2040. }
  2041.  
  2042.  
  2043.  
  2044. void
  2045. freeareas (void)
  2046. {
  2047. struct areas *a;
  2048.  
  2049.     while (Areas) {
  2050.         a = Areas;
  2051.         Areas = Areas->next;
  2052.         if (a->name)    /* should always be, but just in case */
  2053.             free (a->name);
  2054.         free (a);
  2055.     }
  2056. }
  2057.